package com.zhuhao.utils.beanutil;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * 使用beanWrapper进行属性操作
 * @author halk
 * @date 2025/10/16 14:53
 **/
public class BeanUtilDemo {

    private UserEntity userEntity;

    @Before
    public void before() {
        userEntity = new UserEntity()
                .setName("halk")
                .setAge(18)
                .setPhoneList(new ArrayList<String>() {{
                    add("小米");
                    add("红米");
                }})
                .setCar(new UserEntity.Car().setName("长安汽车"))
                .setHeadsetMap(
                        new HashMap<String, String>() {
                            {
                                put("有线耳机", "插孔");
                                put("无线耳机", "小米");
                            }
                        }
                )
                .setCarList(new ArrayList<UserEntity.Car>() {{
                    add(new UserEntity.Car()
                            .setName("小汽车")
                            .setGoodsList(
                                    new ArrayList<UserEntity.Goods>() {
                                        {
                                            add(new UserEntity.Goods().setName("抽纸").setType("物品"));
                                        }
                                    }
                            )
                    );
                }});
    }

    /**
     * 获取属性
     */
    @Test
    public void queryTest() {
        //打印参数
        JSON json = JSONUtil.parse(userEntity);
        System.out.println(json.toJSONString(2));

        //对于一个对象，获取属性值
        Object obj = userEntity;
        BeanWrapper beanWrapper = new BeanWrapperImpl(obj);
        System.out.println("通过反射获取属性值");
        System.out.println("属性值: " + beanWrapper.getPropertyValue("name"));
        System.out.println("属性的属性值: " + beanWrapper.getPropertyValue("car.name"));
        System.out.println("list属性值: " + beanWrapper.getPropertyValue("carList"));
        System.out.println("list中第一个对象: " + beanWrapper.getPropertyValue("carList[0]"));
        System.out.println("list中第一个对象的name属性: " + beanWrapper.getPropertyValue("carList[0].name"));
        System.out.println("list中第一个对象的list第一个对象的name属性: " + beanWrapper.getPropertyValue("carList[0].goodsList[0].type"));
        System.out.println("map中的key对应的value: " + beanWrapper.getPropertyValue("headsetMap[无线耳机]"));

    }

    /**
     * 设置属性
     */
    @Test
    public void setTest() {
        //打印参数
        JSON json = JSONUtil.parse(userEntity);
        System.out.println(json.toJSONString(2));

        //对于一个对象，设置属性值
        Object obj = userEntity;
        BeanWrapperImpl beanWrapper = new BeanWrapperImpl(obj);

        System.out.println("--");
        System.out.println("通过BeanWrapper设置属性值");
        System.out.println("设置属性值前:" + beanWrapper.getPropertyValue("name"));
        beanWrapper.setPropertyValue("name", "halk设置后");
        System.out.println("设置属性值后:" + beanWrapper.getPropertyValue("name"));

        System.out.println("像map中添加一个值: " );
        beanWrapper.setPropertyValue("headsetMap[新加的key]", "新加的value");
        System.out.println("map中的key对应的value: " + beanWrapper.getPropertyValue("headsetMap[新加的key]"));


        Object name = BeanUtil.getProperty(userEntity, "name");
        System.out.println(name);
    }

    /**
     * hutool也有类似工具，实测和spring的BeanWrapperImpl基本操作一样
     */
    @Test
    public void hutoolTest() {
        //打印参数
        JSON json = JSONUtil.parse(userEntity);
        System.out.println(json.toJSONString(2));

        System.out.println((Object) BeanUtil.getProperty(userEntity, "name"));
        System.out.println((Object) BeanUtil.getProperty(userEntity, "car.name"));
        System.out.println((Object) BeanUtil.getProperty(userEntity, "carList[0]"));
        System.out.println((Object) BeanUtil.getProperty(userEntity, "carList[0].name"));
        System.out.println((Object) BeanUtil.getProperty(userEntity, "headsetMap[无线耳机]"));

        BeanUtil.setFieldValue(userEntity, "name", "halk设置后");
        System.out.println((Object) BeanUtil.getProperty(userEntity, "name"));

        BeanUtil.setProperty(userEntity, "name", "halk设置后2");
        System.out.println((Object) BeanUtil.getProperty(userEntity, "name"));

        BeanUtil.setProperty(userEntity, "headsetMap[新加的key]", "新加的value");
        System.out.println((Object) BeanUtil.getProperty(userEntity, "headsetMap[新加的key]"));
    }

    /**
     * bean to map
     * map to bean
     * 转换后实际是创建了一个新的对象
     */
    @Test
    public void hutoolTest2() {
        //map to bean
        //bean to map
        Map<String, Object> stringObjectMap = BeanUtil.beanToMap(userEntity);
        System.out.println(stringObjectMap);

        UserEntity userEntity1 = BeanUtil.toBean(stringObjectMap, UserEntity.class);
        System.out.println(userEntity1);
        System.out.println(userEntity1 == userEntity);

        //将map中的覆盖填充到对象中
        System.out.println(userEntity);
        HashMap<String, Object> targetMap = new HashMap<>();
        targetMap.put("name", "小红");
        targetMap.put("age", 20);
        UserEntity userEntity2 = BeanUtil.fillBeanWithMap(targetMap, userEntity, true);
        System.out.println(userEntity2);
    }

    /**
     * copy list
     */
    @Test
    public void hutoolTest3() {
        ArrayList<UserEntity> sourceList = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            sourceList.add(new UserEntity().setAge(i).setName("halk" + i).setCar(new UserEntity.Car().setName("小汽车" + i)));
        }

        List<UserEntity> targetList = BeanUtil.copyToList(sourceList, UserEntity.class);
        System.out.println(sourceList == targetList);
        System.out.println(targetList.get(0));

        //验证浅拷贝还是深拷贝
        sourceList.get(0).setName("源头被改");
        //基本类型是值传递不关乎浅拷贝还是深拷贝
        System.out.println("基本类型是值传递不关乎浅拷贝还是深拷贝: " + targetList.get(0).getName());

        UserEntity.Car car = sourceList.get(0).getCar();
        sourceList.get(0).setCar(car.setName("源头被改"));
        //基本类型是值传递不关乎浅拷贝还是深拷贝
        System.out.println("引用类型是浅拷贝: " + targetList.get(0).getCar());
    }
}
